iT邦幫忙

2023 iThome 鐵人賽

DAY 4
1

[Day04] FastAPI 基礎架構

本次的程式碼與目錄結構可以參考 FastAPI Tutorial : Day04 branch

我們昨天做了什麼?

昨天的 branch
我們把 uvicorn 包裝成 run.py ,並且加上 .env 方便設定環境變數
可以直接透過 python run.py --<mode> 來啟動 FastAPI
但我們還沒有講解 main.py 中 FastAPI 到底做了什麼事情 !

FastAPI 基礎架構

在昨天的 main.py 中,我們其實只有做兩件事情

  • 建立 FastAPI app 的 instance
  • 定義 API
    • HTTP method
    • Python Typing
    • Path parameter Typing
    • Query parameter Typing

建立 FastAPI app

app 是一個 FastAPI 的 instance,我們可以由這個 instance 中定義我們所有的 API
並且 uvicorn 也是透過 import 這個 instance 來啟動 server

from fastapi import FastAPI

app = FastAPI()

定義 API

如果有寫過 express 或是 flask 的朋友,應該對這個語法不陌生
@app.get("/") 這個 decorator 代表這個 function 會來處理進入 /GET request

@app.get("/")
def hello_world():
    return "Hello World"

而另一段

@app.get("/users/{user_id}")
def get_users(user_id: int, qry: str = None):
    return {"user_id": user_id, "query": qry }

代表這個 function 會來處理進入 /users/{user_id}GET request
並且 user_id 是一個 path parameterqry 是一個 query parameter

API HTTP method

除了 get 之外,如果要使用其他 HTTP method ,可以使用以下的語法

  • @app.post("/route")
  • @app.put("/route")
  • @app.delete("/route")
  • @app.patch("/route")
  • @app.HTTP_METHOD("/route") ...etc

Python Typing

在 FastAPI 中,了解 Python Typing 是非常重要的一環
( 會是使用 Typing 可以說已經會 50% FastAPI 了 )

Python 內建的 Typing

可以在 Day04 : syntax_review/typing.py 中看到範例

我們先來看一下為 Python function 加上 Typing 的好處
先來看一些範例 :

def add(x, y):
    return x + y

def merge(a, b):
    return f"{a} with {b}"

def insert(user , db ):
    return db.insert(user)

add 來說,我們可以看到這個 function 的功能是將兩個變數相加
xy 可能是 int str float 甚至是 list
而 function 的定義很簡單,所以我們用起來不太會有問題

但是來看一下 insert 這個 function ,我們可以看到這個 function 的功能是將 user insert 到 db
但我們看不出來 userdict class list 還是 str
同樣的 db 可能是 session connection class
在沒有加上 typing 的情況下,我們容易在使用這個 function 的時候出錯

  • 在 function 的入參數加上 Typing
    可以透過 <var_name> : <type> 來定義
  • 在 function 的回傳值加上 Typing
    可以透過 <fun_name> -> <type> 來定義

加上 Typing 後的 function 如下 :

def add(x: int, y: int) -> int:
    return x + y

def merge(a: str, b: str) -> str:
    return f"{a} with {b}"

def insert(user: dict , db: Session) -> None:
    return db.insert(user)

FastAPI Router Typing

在 FastAPI 中,我們可以透過 typing 來定義 API function 中
path parameterquery parameter的型別

我們先來比較一下有沒有加上 Typing 的差別

# 有加上 Typing
@app.get("/users/{user_id}")
def get_users(user_id: int, qry: str = None):
    return {"user_id": user_id, "query": qry }

# 沒有加上 Typing
@app.get("/items/{item_id}")
def get_items_without_typing(item_id, qry):
    return {"item_id": item_id, "query": qry }

啟動 FastAPI 後,看一下 Swagger UI
user
可以看到 user_id 是一個 intquery 是一個 str
如果我們 user_id 是用 string 在 Swagger UI 中會報錯
user ui error
如果是使用 curl 來呼叫 API 會回傳 422 Unprocessable Entity
user 422
我們可以在 response 中看到 detail 中有 msg 代表 user_id 應該要是 int
能夠及時在定義 router 的時候就發現這個問題 !

item
可以看到 item_idquery 並沒有特別說型態
當我們在接完 DB 之後的測試階段才遇到報錯
就會很難 Debug 了 !

Optional Query parameter

再次觀察剛剛兩個 API 的 Swagger UI 和 code
user
item

user :

@app.get("/users/{user_id}")
def get_users(user_id: int, qry: str = None):
    return {"user_id": user_id, "query": qry }

item :

@app.get("/items/{item_id}")
def get_items_without_typing(item_id, qry):
    return {"item_id": item_id, "query": qry }

可以看到 user 的 query parameter 有 = None ,但 item 的 query parameter 沒有
這代表 item 的 query parameter 是必填的,但 user 的 query parameter 可以不填
如果 item 的 query parameter 不填也會報 422 Unprocessable Entity
item without para

Body 入參 ?

剛剛加上的 Typing 是用來定義 path parameterquery parameter 的型別
那如果我們想要定義 request body 的型別呢 ?
我們會在明天談到 FastAPI 中由 pydantic提供
另一個也很重要的概念: Schema


上一篇
[Day03] FastAPI 設定與 Uvicorn 包裝
下一篇
[Day05] FastAPI : Schema & Pydantic
系列文
FastAPI 如何 Fast ? 框架入門、實例、重構與測試31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言